#include "GameManager.h"
#include "GameState.h"
#include "Config.h"
#include "ChatBox.h"

using namespace Ogre;

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include "../res/resource.h"
#endif

template<> GameManager* Singleton<GameManager>::ms_Singleton = 0;

GameManager::GameManager() :
	mRoot(0),
	mWindow(0),
	mDeviceManager(0),
	mGUIManager(0)
{
}

GameManager::~GameManager()
{
	// Clean up all the states
	while (!mStates.empty()) {
		mStates.back()->exit();
		mStates.pop_back();
	}

	// Remove self as a Window listener
	WindowEventUtilities::removeWindowEventListener(mWindow, this);

	// Clean up
	windowClosed(mWindow);

	// Delete Root
	if (mRoot)
		delete mRoot;
	mRoot = 0;	
}

void GameManager::start(GameState* state)
{
	// Create new root
	mRoot = new Root();

	// Create scene manager for our game
	mRoot->createSceneManager(ST_GENERIC, "plitzScene");

	// Parse the file in resources.cfg to grab resource locations
	setupResources();

	// Display config screen to choose graphics settings
	bool carryOn = configure();
	if (!carryOn) return;

	// Create any resource listeners (for loading screens) // TODO!!
	createResourceListener();

	// Load resources, manually load textures
	loadResources();
	
	// Load Configurations
	Config::getInstance()->loadConfig("config.xml","Config");

	// Set up Device and UI Managers
	mDeviceManager = new DeviceManager(mRoot->getAutoCreatedWindow());
	mGUIManager = new GUIManager(mRoot->getAutoCreatedWindow());

	// Set up Sound Manager
	soundManager = new OgreAL::SoundManager();

	// Register Game Manager to listen every frame
	mRoot->addFrameListener(this);
	
	// Register callbacks for buffered input
	mDeviceManager->mKeyboard->setEventCallback(this);
	mDeviceManager->mMouse->setEventCallback(this);

	// Initialize Chat Box for use
	ChatBox* mChatBox = ChatBox::getSingletonPtr();
	mChatBox = new ChatBox();
	mChatBox->init();

	windowResized(mWindow);

	// Register as a Window listener
	WindowEventUtilities::addWindowEventListener(mWindow, this);

	// Go to the start state i.e. IntroState
	changeState(state);

	mRoot->startRendering();
}

void GameManager::changeState(GameState* state)
{
	// cleanup the current state
	if ( !mStates.empty() ) {
		mStates.back()->exit();
		mStates.pop_back();
	}

	// store and init the new state
	mStates.push_back(state);
	mStates.back()->enter();
}

void GameManager::pushState(GameState* state)
{
	// pause current state
	if ( !mStates.empty() ) {
		mStates.back()->pause();
	}

	// store and init the new state
	mStates.push_back(state);
	mStates.back()->enter();
}

void GameManager::popState()
{
	// cleanup the current state
	if ( !mStates.empty() ) {
		mStates.back()->exit();
		mStates.pop_back();
	}

	// resume previous state
	if ( !mStates.empty() ) {
		mStates.back()->resume();
	}
}

void GameManager::setupResources(void)
{
	// load resource paths from config file
	ConfigFile cf;
	cf.load("resources.cfg");

	// go through all settings in the file
	ConfigFile::SectionIterator seci = cf.getSectionIterator();

	String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		ConfigFile::SettingsMultiMap *settings = seci.getNext();
		ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin() ; i != settings->end() ; ++i)
		{
			typeName = i->first;
			archName = i->second;
			ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}
}

bool GameManager::configure(void)
{
	// Show the configuration dialog and initialise the system
	if(mRoot->showConfigDialog())
	{
		// If returned true, user clicked OK so initialise
		// Here we choose to let the system create a default rendering window by passing 'true'
		mWindow = mRoot->initialise(true);

		// Let's add a nice window icon
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		HWND hwnd;
		mWindow->getCustomAttribute("WINDOW", (void*)&hwnd);
		LONG iconID   = (LONG)LoadIcon( GetModuleHandle(0), MAKEINTRESOURCE(IDI_APPICON) );
		SetClassLong( hwnd, GCL_HICON, iconID );
#endif
		return true;
	}
	else return false;
}

void GameManager::createResourceListener(void)
{
}

void GameManager::loadResources(void)
{
	// Initialise the rest of the resource groups, parse scripts etc
	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	// Load texture sprites for UI
	Ogre::TextureManager::getSingleton().load("plitzkrieg1.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("healthbar_left.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("healthbar_right.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("healthbar_blood.png","Plitzkrieg");

	// Load texture sprites for medals
	Ogre::TextureManager::getSingleton().load("redmedal.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("bluemedal.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("greymedal.png","Plitzkrieg");

	// Load texture sprites for winlosedraw notices
	Ogre::TextureManager::getSingleton().load("redwin.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("bluewin.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("drawgame.png","Plitzkrieg");

	Ogre::TextureManager::getSingleton().load("ready.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("set.png","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("go.png","Plitzkrieg");


	// Load texture sprites for SpaceDock
	Ogre::TextureManager::getSingleton().load("box.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("brass.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("centersquare.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("circletop.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("floortexture2.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("floortexture.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("meteor02.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("random.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("rohrkreuz2.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("rombusmetall.jpg","Plitzkrieg");	
	Ogre::TextureManager::getSingleton().load("shiphull.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("techno07.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall1.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall2.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall3.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall4.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall5.jpg","Plitzkrieg");
	Ogre::TextureManager::getSingleton().load("wall6.jpg","Plitzkrieg");
}

bool GameManager::keyPressed(const OIS::KeyEvent &arg)
{
	return mStates.back()->keyPressed(arg);
}

bool GameManager::keyReleased(const OIS::KeyEvent &arg)
{
	return mStates.back()->keyReleased(arg);
}

bool GameManager::mouseMoved( const OIS::MouseEvent &arg )
{
	return mStates.back()->mouseMoved(arg);
}

bool GameManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	return mStates.back()->mousePressed(arg, id);
}

bool GameManager::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	return mStates.back()->mouseReleased(arg, id);
}

bool GameManager::frameStarted(const FrameEvent& evt)
{
	if(mWindow->isClosed())
		return false;
	// call frameStarted of current state
	return mStates.back()->frameStarted(evt);
}

bool GameManager::frameEnded(const FrameEvent& evt)
{
	// call frameEnded of current state
	return mStates.back()->frameEnded(evt);
}

void GameManager::windowResized(RenderWindow* rw)
{
	unsigned int width, height, depth;
	int left, top;
	rw->getMetrics(width, height, depth, left, top);

	const OIS::MouseState &ms = mDeviceManager->mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

void GameManager::windowClosed(RenderWindow* rw)
{
	//Only close for window that created OIS (the main window in these demos)
	if( rw == mWindow )
	{
		// Clean up input devices
		if (mDeviceManager)
		{
			delete mDeviceManager;
			mDeviceManager = 0;
		}
		if (mGUIManager)
		{
			delete mGUIManager;
			mGUIManager = 0;
		}
	}
}

GameManager* GameManager::getSingletonPtr(void)
{
	return ms_Singleton;
}

GameManager& GameManager::getSingleton(void)
{  
	assert(ms_Singleton);
	return *ms_Singleton;
}